﻿using Microsoft.EntityFrameworkCore;
using NewRetail.Application.Components.Platform.Entity;
using NewRetail.Application.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;

namespace NewRetail.Application.Components.Platform
{
    public class PosSalesPayFlowFilterDto : PagingRequestDto
    {
        public string warehouseId { get; set; }
        public string cashierId { get; set; }
        public string cashierName { get; set; }

        public DateTime? startTime { get; set; }
        public DateTime? endTime { get; set; }

        public string flowNo { get; set; }
        public string payWay { get; set; }
    }

    public interface IPosSalesPayFlowService
    {
        Task<PosSalesFlow[]> AttachCashRegister(PosSalesFlow[] data);
        Task<PosPayFlow[]> AttachCashier(PosPayFlow[] data);
        /// <summary>
        /// 订单流水支付显示
        /// </summary>
        /// <param name="inputDto"></param>
        /// <param name="showAll">是否显示现金的支付方式，true:显示，false:不显示 。 默认不显示</param>
        /// <returns></returns>
        Task<PagedResultDto<PosPayFlow>> QueryPosPayFlowSales(PosSalesPayFlowFilterDto inputDto, bool showAll = false);

    }

    public class PosSalesPayFlowService : MyApplicationService, IPosSalesPayFlowService
    {
        private readonly IRepository<PosPayFlow> posPayFlows;

        public PosSalesPayFlowService(IRepository<PosPayFlow> posPayFlows)
        {
            this.posPayFlows = posPayFlows;
        }

        public async Task<PosSalesFlow[]> AttachCashRegister(PosSalesFlow[] data)
        {
            var db = await this.posPayFlows.GetDbContextAsync();

            await db.AttachData<PosCashRegister, PosSalesFlow>(data,
                idGetter: x => x.cashRegisterID,
                action: (m, arr) => m.PosCashRegister = arr.FirstOrDefault());

            return data;
        }

        public async Task<PosPayFlow[]> AttachCashier(PosPayFlow[] data)
        {
            var db = await this.posPayFlows.GetDbContextAsync();

            await db.AttachData<PosCashier, PosPayFlow>(data,
                idGetter: x => x.cashierID,
                action: (m, arr) => m.PosCashier = arr.FirstOrDefault());

            return data;
        }

        #region 订单流水支付显示
        /// <summary>
        /// 订单流水支付显示
        /// </summary>
        /// <param name="inputDto"></param>
        /// <param name="showAll">是否显示现金的支付方式，true:显示，false:不显示 。 默认不显示</param>
        /// <returns></returns>
        public async Task<PagedResultDto<PosPayFlow>> QueryPosPayFlowSales(PosSalesPayFlowFilterDto inputDto, bool showAll = false)
        {
            var db = await this.posPayFlows.GetDbContextAsync();
            var posPayFlows = db.Set<PosPayFlow>().AsNoTracking();
            posPayFlows = posPayFlows.WhereIf(inputDto.startTime != null, x => x.payTime >= inputDto.startTime.Value);
            posPayFlows = posPayFlows.WhereIf(inputDto.endTime != null, x => x.payTime < inputDto.endTime.Value);

            if (!string.IsNullOrWhiteSpace(inputDto.flowNo))
            {
                posPayFlows = posPayFlows.Where(x => x.flowNo.Contains(inputDto.flowNo));
            }
            if (!string.IsNullOrWhiteSpace(inputDto.warehouseId))
            {
                posPayFlows = posPayFlows.Where(x => x.warehouseID == inputDto.warehouseId);
            }
            posPayFlows = posPayFlows.WhereIf(!string.IsNullOrWhiteSpace(inputDto.cashierId),
                x => x.cashierID == inputDto.cashierId);

            if (!string.IsNullOrWhiteSpace(inputDto.cashierName))
            {
                var cashierIds = db.Set<PosCashier>().AsNoTracking()
                    .Where(x => x.cashierName.Contains(inputDto.cashierName))
                    .Select(x => x.Id);
                posPayFlows = posPayFlows.Where(x => cashierIds.Contains(x.cashierID));
            }

            if (!string.IsNullOrWhiteSpace(inputDto.payWay))
            {
                posPayFlows = posPayFlows.Where(x => x.payWay == inputDto.payWay);
            }
            //获取所有找零的记录结果
            var resultAD = posPayFlows.Where(x => x.payWay == "AD");
            //剔除所有找零和自动抹零记录的结果
            var payWayFilter = new List<string> { "X", "AD" };
            var resultExceptADX = await posPayFlows.Where(x => !payWayFilter.Contains(x.payWay)).ToListAsync();
            //将找零记录合并分组
            var resultGpAD = await resultAD.GroupBy(g => new { g.flowNo, g.warehouseID })
                .Select(x => new
                {
                    flowNo = x.Key.flowNo,
                    warehouseID = x.Key.warehouseID,
                    payAmount = x.Sum(y => y.payAmount)
                }).ToListAsync();

            var result1 = resultExceptADX.GroupJoin(resultGpAD, ct => $"{ct.warehouseID}{ct.flowNo}", cs => $"{cs.warehouseID}{cs.flowNo}", (x, y) => new { posPayFlows = x, gpADInfos = y })
                .SelectMany(xy => xy.gpADInfos.DefaultIfEmpty(), (x, y) => new { posPayFlows = x.posPayFlows, gpADInfos = y }).ToList();
            var result = result1
                .Select(s => new PosPayFlow
                {
                    warehouseID = s.posPayFlows.warehouseID,
                    flowNo = s.posPayFlows.flowNo,
                    cashierID = s.posPayFlows.cashierID,
                    payWay = s.posPayFlows.payWay,
                    payAmount = s.posPayFlows.payWay == "A" ? s.posPayFlows.payAmount - (s.gpADInfos == null ? 0 : s.gpADInfos.payAmount) : s.posPayFlows.payAmount,
                    saleAmount = s.posPayFlows.saleAmount,
                    cardNumber = s.posPayFlows.cardNumber,
                    memberID = s.posPayFlows.memberID,
                    payTime = s.posPayFlows.payTime
                }).ToList();

            if (showAll)
                result = result.OrderByDescending(x => x.payTime).ToList();
            else
                //这边先去掉所有的现金支付记录
                result = result.Where(x => x.payWay != "A").OrderByDescending(x => x.payTime).ToList();

            var response = new PagedResultDto<PosPayFlow>();
            response.TotalCount = result.Count();

            int pageSize = inputDto.PageSize == 0 ? 100 : inputDto.PageSize, pageIndex = inputDto.Page == 0 ? 1 : inputDto.Page;
            //总页数
            var pageCount = (result.Count() + pageSize - 1) / pageSize;
            result = result.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();

            response.Items = result;

            await db.AttachData<PosCashier, PosPayFlow>(result, x => x.cashierID,
                (m, arr) => m.PosCashier = arr.FirstOrDefault());

            return response;
        }
        #endregion
    }
}
